package com.gitee.l0km.codegen.base.generator;

import static com.google.common.base.Preconditions.checkNotNull;

import java.io.File;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;

import com.gitee.l0km.codegen.base.CodeGenUtils;
import com.gitee.l0km.codegen.base.CreateInterfaceSourceConstants;
import com.gitee.l0km.codegen.base.DuplicatedConstants;
import com.gitee.l0km.com4j.base.ClassLoaderUtils;
import com.gitee.l0km.com4j.base.MiscellaneousUtils;
import com.gitee.l0km.com4j.base.SimpleLog;
import com.gitee.l0km.com4j.cli.AbstractConfiguration;
import com.gitee.l0km.com4j.cli.Context;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 * 代码生成器通用参数对象
 * @author guyadong
 *
 */
public class GeneratorConfiguration extends AbstractConfiguration implements CreateInterfaceSourceConstants,
		DuplicatedConstants {
	public static final String DEFAULT_OUT = ".";
	public static final String DEFAULT_ROOT = "./templates";
	public static final String DEFAULT_FOLDER = ".";
	public static final String DEFAULT_INCLUDE = "includes";
	public static final String DEFAULT_LOADER= "class";
	private File outputLocation;
	private String templateRoot;
	private String templateFolder;
	private String includeFolder;
	private Set<String> excludeVms;
	private Set<String> includeVms;
	private String sourcePackage;
	private String resourceLoaderType;
	protected final Context defaultValue = Context.builder()
			.addProperty(OUTPUT_LOCATION_OPTION_LONG, new File(DEFAULT_OUT))
			.addProperty(TEMPLATE_ROOT_OPTION_LONG, DEFAULT_ROOT)
			.addProperty(TEMPLATE_FOLDER_OPTION_LONG, DEFAULT_FOLDER)
			.addProperty(TEMPLATE_INCLUDE_OPTION_LONG, DEFAULT_INCLUDE)
			.addProperty(EXCLUDE_VMS_OPTION_LONG, "")
			.addProperty(INCLUDE_VMS_OPTION_LONG, "")
			.addProperty(RESOURCE_LOADER_OPTION_LONG, DEFAULT_LOADER)
			.build();
	@Override
	protected Map<String, Object> getDefaultValueMap() {
		return defaultValue.getContext();
	}

	@Override
	public void loadConfig(Options options, CommandLine cmd) throws ParseException {
		super.loadConfig(options, cmd);
		outputLocation = getProperty(OUTPUT_LOCATION_OPTION_LONG);
		templateRoot = getProperty(TEMPLATE_ROOT_OPTION_LONG);
		templateFolder = getProperty(TEMPLATE_FOLDER_OPTION_LONG);
		includeFolder = getProperty(TEMPLATE_INCLUDE_OPTION_LONG);
		String evms = getProperty(EXCLUDE_VMS_OPTION_LONG);
		excludeVms = Sets.newHashSet(MiscellaneousUtils.elementsOf(evms));
		String ivms = getProperty(INCLUDE_VMS_OPTION_LONG);
		includeVms = Sets.newHashSet(MiscellaneousUtils.elementsOf(ivms));
		sourcePackage = getProperty(PACKAGE_OPTION_LONG);
		resourceLoaderType = getProperty(RESOURCE_LOADER_OPTION_LONG);
	}

	/**
	 * @return outputLocation
	 */
	public File getOutputLocation() {
		return outputLocation;
	}

	/**
	 * @return templateRoot
	 */
	public String getTemplateRoot() {
		return templateRoot;
	}

	/**
	 * @return templateFolder
	 */
	public String getTemplateFolder() {
		return templateFolder;
	}

	/**
	 * @return includeFolder
	 */
	public String getIncludeFolder() {
		return includeFolder;
	}

	/**
	 * @return excludeVms
	 */
	public Set<String> getExcludeVms() {
		return excludeVms;
	}

	/**
	 * @return includeVms
	 */
	public Set<String> getIncludeVms() {
		return includeVms;
	}

	/**
	 * @return sourcePackage
	 */
	public String getSourcePackage() {
		return sourcePackage;
	}

	/**
	 * @return defaultValue
	 */
	public Context getDefaultValue() {
		return defaultValue;
	}

	/**
	 * @param templateFolder 要设置的 templateFolder
	 */
	public void setTemplateFolder(String templateFolder) {
		this.templateFolder = templateFolder;
	}

	public String getResourceLoaderType() {
		return resourceLoaderType;
	}
	public boolean useClasspathResourceLoader(){
		return DEFAULT_LOADER.equals(getResourceLoaderType());
	}
	public List<String> getListProperty(String name){
		return MiscellaneousUtils.elementsOf((String)getProperty(name));
	}
	public HashSet<String> getSetProperty(String name){
		return Sets.newHashSet(MiscellaneousUtils.elementsOf((String)getProperty(name)));
	}

	public void readClassEntry(String propertyName, Map<Class<?>, List<String>>  input) {
		String[] entries = getProperty(propertyName);
		if(entries != null){
			for(String str : entries){
				String[] entry = str.split(":");
				try {
					List<String> names = MiscellaneousUtils.elementsOf(entry[1]);
					if(!names.isEmpty()){
						checkNotNull(input,"input is null").put(CodeGenUtils.forName(entry[0]),names);
					}
				} catch (ClassNotFoundException e) {
					SimpleLog.log(e.toString());
				}
			}
		}
	}

	public Map<Class<?>, List<String>> getClassEntry(String propertyName) {
		Map<Class<?>, List<String>>  input = Maps.newHashMap();
		readClassEntry(propertyName,input);
		return input;
	}
	
	/**
	 * @return excludeMethods
	 */
	public Map<Class<?>, List<String>> getExcludeMethods() {
		return Collections.emptyMap();
	}

	/**
	 * @return includeMethods
	 */
	public Map<Class<?>, List<String>> getIncludeMethods() {
		return Collections.emptyMap();
	}

	/**
	 * 读取{@code key}指定的属性值(String),将分号/逗号/空格分割的类名列表转为类对集合
	 * @param key
	 * @param classpath 类搜索路径
	 * @param initialize 是否初始化类
	 * @throws ParseException 没有找到类
	 * @since 3.3.0
	 */
	protected List<Class<?>> getClasses(String key, String classpath, boolean initialize)
			throws ParseException {
		try {
			return ClassLoaderUtils.loadClasses((String) getProperty(key), classpath, initialize,
					CodeGenUtils.getProjectClassLoader());
		} catch (ClassNotFoundException e) {
			throw new ParseException("ClassNotFoundException:" + e.getMessage());
		}
	}
}
